/*
 * Copyright (C) Michael Martin & Antonio Carrozzini (TBJD)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package org.tbjd.client.dndControllers.gantt;

import java.util.HashMap;
import java.util.Map;

import org.tbjd.client.borderDetectors.GanttBorderNotifier;
import org.tbjd.client.constants.GanttConstants;
import org.tbjd.client.constants.NotificationsConstants;
import org.tbjd.client.exceptions.NoUpperDecisionmakerFoundException;
import org.tbjd.client.exceptions.NoUpperMediatorFoundException;
import org.tbjd.client.exceptions.TBJDException;
import org.tbjd.client.guis.gantt.GanttItemContainerGui;
import org.tbjd.client.interfaces.BorderTrigger;
import org.tbjd.client.interfaces.Decisionmaker;

import com.allen_sauer.gwt.dnd.client.PickupDragController;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * <p>
 * The drag controller for a {@link org.tbjd.client.guis.gantt.items.AbstractGanttItem AbstractItem}
 * </p>
 * <p>
 * It allows a AbstractGanttItem to be dragged on the {@link org.tbjd.client.guis.gantt.GanttGui GanttGui}
 * </p>
 * 
 * 
 * @author Michael Martin
 * @author Antonio Carrozzini
 * @version 1.0
 * 
 */
public class GanttItemDragController extends PickupDragController implements Decisionmaker, BorderTrigger {

	private GanttBorderNotifier ganttBorderNotifier = null;
	private Map<Integer, Object> map = null;
	private Integer mouseOrigin = null;

	public GanttItemDragController(AbsolutePanel boundaryPanel, boolean allowDroppingOnBoundaryPanel) {
		super(boundaryPanel, allowDroppingOnBoundaryPanel);
		addBorderNotifier();
	}

	public void dragStart() {
		super.dragStart();

		// put the dragged item in a map
		this.map = new HashMap<Integer, Object>();
		this.map.put(NotificationsConstants.TASKITEM_DRAGGING_START, this.context.draggable);

		// tell the GanttItemContainerGui to decide
		decide(this.map);

		// reset the borderDetectedHorizontalOffset
		GanttItemContainerGui.borderDetectedHorizontalOffset = 0;
	}

	public void dragMove() {
		super.dragMove();

		// catch x origin
		if (mouseOrigin == null) {
			System.out.println("GanttItemDragController.dragMove mouse origin = " + this.mouseOrigin);
			this.mouseOrigin = this.context.mouseX;
		}

		// call the ganttBorderNotifier to move ganttItems in the GanttItemContainerGui
		this.ganttBorderNotifier.mouseEvent(this.context.boundaryPanel, this.context.draggable, this.context.mouseX
				+ GanttConstants.SCROLL_HORIZONTAL_OFFSET, this.context.mouseY);

		// put the dragged item with its axis drag start origins in a map
		this.map = new HashMap<Integer, Object>();
		this.map.put(NotificationsConstants.TASKITEM_DRAGGING, this.context.draggable);
		this.map.put(NotificationsConstants.TASKITEM_DRAGGING_X, this.context.mouseX);
		this.map.put(NotificationsConstants.TASKITEM_DRAGGING_Y, this.context.mouseY);

		// and add the offset to the map
		this.map.put(NotificationsConstants.DRAGGING_OFFSET, new Integer(this.context.mouseX - this.mouseOrigin));
		System.out.println("GanttItemDragController.dragMove offset =" + (this.context.mouseX - this.mouseOrigin));
		System.out.println("\t this.context.mouseX =" + this.context.mouseX);
		System.out.println("\t this.mouseOrigin =" + this.mouseOrigin);

		decide(this.map);
	}

	public void dragEnd() {
		super.dragEnd();

		// reset mouse origin
		this.mouseOrigin = null;

		// cancel borderNotifier
		this.ganttBorderNotifier.cancel();

		// put the dragged item in a map
		this.map = new HashMap<Integer, Object>();
		this.map.put(NotificationsConstants.TASKITEM_DRAGGING_STOP, null);

		// tell the GanttItemContainerGui to decide
		decide(this.map);
	}

	public void decide(Object action) {
		handle(action);
	}

	public void handle(Object action) {
		try {
			delegate(action);

		} catch (NoUpperDecisionmakerFoundException e) {
			e.printStackTrace();

		} catch (NoUpperMediatorFoundException e) {
			e.printStackTrace();
		}
	}

	public void delegate(Object action) throws NoUpperDecisionmakerFoundException, NoUpperMediatorFoundException {
		Widget parent = ((Widget) this.context.draggable).getParent();
		while (parent != null && parent instanceof Decisionmaker == false) {
			parent = ((Widget) parent).getParent();
		}
		if (parent != null) {
			try {
				((Decisionmaker) parent).decide(action);
			} catch (TBJDException e) {
				e.printStackTrace();
			}
		} else {
			throw new NoUpperDecisionmakerFoundException();
		}

	}

	public void addBorderNotifier() {
		this.ganttBorderNotifier = GanttBorderNotifier.getInstance();
	}

	public void defineTrigger() {
		// no trigger definition is needed because we trigger on the dragMove method()
	}

}
